package com.yuanda.erp9.syn.util;

import com.yuanda.erp9.syn.exception.TargetServerException;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description: 多线程网络文件下载工具类
 * @Params:
 * @Return:
 * @Author: Mr.myq
 * @Date: 2023/2/313:34
 */
@Slf4j
public class ManyThreadFileDownloadUtil {

    private static Map<String, AtomicInteger> stringAtomicIntegerMap = new ConcurrentHashMap<>();

    /**
     * @Description: 提交任务
     * @Params:
     * @Return:
     * @Author: Mr.myq
     * @Date: 2023/2/313:31
     */
    public static void commitTask(String fileUrlStr, String dir, String fileName) {
        File file = new File(dir + "/" + fileName);
        //删除文件
        if (file.exists()) {
            if (file.delete()) {
                log.info("*********************删除Future-" + file.getName() + "本地临时文件成功********************");
            }
        }
        int maxThreadCount = 2;
        long s = System.currentTimeMillis();
        HttpURLConnection conn = null;
        ExecutorService executorService = Executors.newFixedThreadPool(maxThreadCount);
        stringAtomicIntegerMap.put(fileName, new AtomicInteger(0));
        try {
            URL url = new URL(fileUrlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setRequestMethod("HEAD");
            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                int contentLength = conn.getContentLength();
                int range = contentLength / maxThreadCount;
                int startIndex = 0, endIndex = 0;
                for (int x = 0; x < maxThreadCount; x++) {
                    startIndex = x * range;
                    endIndex = (x + 1) * range;
                    if (x == maxThreadCount - 1) {
                        endIndex = contentLength;
                    }

                    manyThreadDownload(executorService, startIndex, endIndex, fileUrlStr, dir, fileName, contentLength);
                }
            }
            executorService.shutdown();
            while (true) {
                if (executorService.isTerminated()) {
                    log.debug(" 总共耗时：" + (System.currentTimeMillis() - s) / 1000 + "秒");
                    break;
                }
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            log.error("使用HEAD方法探测Future文件异常：" + e);
            throw new TargetServerException("使用HEAD方法探测Future文件异常");
        } finally {
            if (conn != null)
                conn.disconnect();
        }


    }


    /**
     * @Description: 开始多线程下载并获取“实时'百分比
     * @Params:
     * @Return:
     * @Author: Mr.myq
     * @Date: 2023/2/313:31
     */
    private static void manyThreadDownload(ExecutorService executorService, int startIndex, int endIndex, String fileUrlStr, String dir, String fileName, int contentLength) {
        Thread thread = null;
        thread = new Thread(() -> {
            HttpURLConnection conn = null;
            try {
                URL url = new URL(fileUrlStr);
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);
                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); //固定写法，请求部分资源
                int responseCode = conn.getResponseCode(); // 206表示请求部分资源
                if (responseCode == 206) {
                    File file = new File(dir + "/" + fileName);
                    RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
                    randomAccessFile.seek(startIndex);
                    InputStream is = conn.getInputStream();
                    int len = -1;
                    int currThreadSum = 0;
                    int index = endIndex - startIndex;
                    byte[] buffer = new byte[1024 * 20];
                    long begin = System.currentTimeMillis();
                    while ((len = is.read(buffer)) != -1) {
                        randomAccessFile.write(buffer, 0, len);
                        currThreadSum += len;
                        AtomicInteger atomicInteger = stringAtomicIntegerMap.get(fileName);
                        atomicInteger.addAndGet(len);

                        /**
                         * 间隔打印日志输出
                         */
                        while ((System.currentTimeMillis() - begin) > 5000) {
                            printF(fileName, currThreadSum, index, startIndex, endIndex);
                            printSumF(fileName, atomicInteger, contentLength);

                            begin = System.currentTimeMillis();
                            break;
                        }
                    }

                    randomAccessFile.close();
                    is.close();
                }

            } catch (Exception e) {
                executorService.shutdownNow();
                log.error("Future多线程下载文件异常：" + e.toString());
                throw new TargetServerException("Future多线程下载文件异常", 4, fileName);
            } finally {
                if (conn != null)
                    conn.disconnect();
            }
        });
        executorService.execute(thread);
    }


    /**
     * @Description: 打印总的下载量
     * @Params:
     * @Return:
     * @Author: Mr.myq
     * @Date: 2023/2/614:33
     */
    private static void printSumF(String fileName, AtomicInteger sumLengthAtomic, int contentLength) {
        double z = new BigDecimal(String.valueOf(sumLengthAtomic)).divide(new BigDecimal(String.valueOf(contentLength)), 2, RoundingMode.HALF_UP).doubleValue();
        int a = (int) (z * 100);
        int alignment = 100 - a;
        StringBuilder sb = new StringBuilder();
        while (a != 0) {
            sb.append(">");
            a--;
        }
        while (alignment > 0) {
            sb.append(" ");
            alignment--;
        }
        sb.append((int) (z * 100)).append("%");
        String startIndexStr = "";
        int i = (contentLength + "").length();
        while (i-- > 0) {
            startIndexStr += "0";
        }
        log.info("当前线程：" + Thread.currentThread().getName() + "正在下载" + fileName + "文件。下载总量: [startIndex(" + (startIndexStr) + ")---endIndex(" + contentLength + ")]" + ", Downloading...: [" + sb.toString() + "]");
    }


    /**
     * @Description: 输出download日志
     * @Params:
     * @Return:
     * @Author: Mr.myq
     * @Date: 2023/2/317:28
     */
    private static void printF(String fileName, int currThreadSum, int index, int startIndex, int endIndex) {
        double z = new BigDecimal(String.valueOf(currThreadSum)).divide(new BigDecimal(String.valueOf(index)), 2, RoundingMode.HALF_UP).doubleValue();
        int a = (int) (z * 100);
        int alignment = 100 - a;
        StringBuilder sb = new StringBuilder();
        while (a != 0) {
            sb.append("=");
            a--;
        }
        while (alignment > 0) {
            sb.append(" ");
            alignment--;
        }
        sb.append((int) (z * 100)).append("%");
        String startIndexStr = "";
        if (startIndex == 0) {
            int i = (endIndex + "").length();
            while (i-- > 0) {
                startIndexStr += "0";
            }
        } else {
            startIndexStr = String.valueOf(startIndex);
        }
        log.debug("当前线程：" + Thread.currentThread().getName() + "正在下载" + fileName + "文件。下载区间: [startIndex(" + (startIndexStr) + ")---endIndex(" + endIndex + ")]" + ", Downloading...: [" + sb.toString() + "]");

    }


}
